package com.hilda.HTMLParserTesting.htmlCleaner;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

import org.htmlcleaner.CleanerProperties;
import org.htmlcleaner.CommentNode;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.HtmlNode;
import org.htmlcleaner.SimpleHtmlSerializer;
import org.htmlcleaner.TagNode;
import org.htmlcleaner.TagNodeVisitor;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.hilda.HTMLParserTesting.CrawDroidActivity;
import com.hilda.HTMLParserTesting.utils.SdCardUtils;
import com.hilda.HTMLParserTesting.utils.UrlUnshortCallBack;
import com.hilda.HTMLParserTesting.utils.UrlUnshortUtils;

public class HildaHtmlCleaner implements UrlUnshortCallBack {
	private Context mContext;
	private URL mURL;
	private URL mUnshortURL;
	private SdCardUtils mSdCardUtils;
	private HtmlCleaner mHtmlCleaner;
	private Handler mHandler;
	private UrlUnshortUtils mUrlUtils;
	private String[] mImageFileTypes = { "png", "jpg", "jpeg", "gif" };

	public HildaHtmlCleaner(Context c, Handler handler) {
		mContext = c;
		mSdCardUtils = new SdCardUtils(mContext);
		mHtmlCleaner = new HtmlCleaner();
		mHandler = handler;
		// take default cleaner properties
		CleanerProperties props = mHtmlCleaner.getProperties();
		props.setOmitComments(true);
		props.setAllowHtmlInsideAttributes(true);
		props.setAllowMultiWordAttributes(true);
		props.setRecognizeUnicodeChars(true);
		props.setOmitComments(true);
	}

	@Override
	public void onReceiveServices(int status) {
		// mUnshortURL = mUrlUtils.unshortUrl(mURL.toExternalForm());
		mUrlUtils.unshortUrl(mURL.toExternalForm());
		// DowloadWebTask dowloadWebTask = new DowloadWebTask();
		// dowloadWebTask.execute();
	}

	@Override
	public void onExtractUrl(int status, URL urlUnshort) {
		mUnshortURL = urlUnshort;
		switch (status) {
		case UrlUnshortUtils.UNSHORT_OK:
			if (mUnshortURL != null) {
				Log.v("crawDroid", "HildaHtmlCleaner.parse(): unshort "
						+ mUnshortURL);
				mURL = mUnshortURL;
				DowloadWebTask dowloadWebTask = new DowloadWebTask();
				dowloadWebTask.execute();
			}
			break;
		case UrlUnshortUtils.UNSHORT_LONG_URL:
			Log.v("crawDroid", "HildaHtmlCleaner.parse(): no short URL "
					+ mUnshortURL);
			mURL = mUnshortURL;
			DowloadWebTask dowloadWebTask = new DowloadWebTask();
			dowloadWebTask.execute();
			break;
		case UrlUnshortUtils.UNSHORT_KO:
			Log.e("crawDroid", "HildaHtmlCleaner.parse(): error to unshort");
			break;
		}

		// if (status != UrlUnshortUtils.UNSHORT_TRY_AGAIN
		// && (mUnshortURL != null || status != UrlUnshortUtils.UNSHORT_KO)) {
		// Log.v("crawDroid", "HildaHtmlCleaner.parse(): unshort "
		// + mUnshortURL);
		// mURL = mUnshortURL;
		// DowloadWebTask dowloadWebTask = new DowloadWebTask();
		// dowloadWebTask.execute();
		// } else if (status == UrlUnshortUtils.UNSHORT_LONG_URL) {
		// Log.v("crawDroid", "HildaHtmlCleaner.parse(): no short URL "
		// + mUnshortURL);
		// mURL = mUnshortURL;
		// DowloadWebTask dowloadWebTask = new DowloadWebTask();
		// dowloadWebTask.execute();
		// }

	}

	public void parse(String url) {
		Log.i("crawDroid", "Start HtmlCleaner parser " + url);

		if (!url.endsWith("/"))
			url += "/";

		try {
			mURL = new URL(url);
		} catch (MalformedURLException e) {
			Log.e("crawDroid", ".HtmlCleaner: " + e.getMessage());
		}

		mUrlUtils = new UrlUnshortUtils(this);

	}

	private class DowloadWebTask extends AsyncTask<URL, Void, String> {

		@Override
		protected String doInBackground(URL... urls) {
			String filePath = null;

			try {
				// PARSE
				TagNode node = mHtmlCleaner.clean(mURL);

				getImages(node);
				getCSS(node);

				File file = mSdCardUtils.prepareFile(mURL, null);
				filePath = file.getAbsolutePath();
				SimpleHtmlSerializer serializer = new SimpleHtmlSerializer(
						mHtmlCleaner.getProperties());

				serializer.writeToFile(node, file.getAbsolutePath());

			} catch (MalformedURLException e) {
				Log.e("crawDroid", ".HtmlCleaner: " + e.getMessage());
			} catch (IOException e) {
				Log.e("crawDroid", ".HtmlCleaner: " + e.getMessage());
			}

			return filePath;
		}

		@Override
		protected void onPostExecute(String filePath) {
			Log.i("crawDroid", "Finish HtmlCleaner AsyncTask");
			Message m = new Message();
			m.what = CrawDroidActivity.DOWNLOAD_OK;
			m.obj = filePath;
			mHandler.sendMessage(m);

			super.onPostExecute(null);
		}
	}

	private void getImages(TagNode node) {
		final ArrayList<String> list = new ArrayList<String>();

		// traverse whole DOM and update images to absolute URLs
		node.traverse(new TagNodeVisitor() {
			public boolean visit(TagNode tagNode, HtmlNode htmlNode) {
				if (htmlNode instanceof TagNode) {
					TagNode tag = (TagNode) htmlNode;
					String tagName = tag.getName();
					if ("img".equals(tagName)) {
						String src = tag.getAttributeByName("src");
						if (src != null) {

							if (src.startsWith("htt")) {
								// Check file Type images
								for (String imageFileType : mImageFileTypes) {
									if (src.toLowerCase().endsWith(
											imageFileType)) {
										list.add(src);
									}
								}

							} else {
								if (src.startsWith("/")) {
									src = src.substring(1);
								}
								if (src.contains("//")) {
									src = src.replace("//", "/");
								}
								// Check file Type images
								for (String imageFileType : mImageFileTypes) {
									if (src.toLowerCase().endsWith(
											imageFileType)) {
										list.add(mURL.toExternalForm() + src);
									}
								}

							}

							// Change absolute url path to relative path
							String[] split = src.split("/");
							String filenameImage = split[split.length - 1];

							if (filenameImage.contains("?")) {
								filenameImage = filenameImage.substring(0,
										filenameImage.indexOf("?"));
							}

							tag.setAttribute("src", "images/" + filenameImage);

						}
					}
				} else if (htmlNode instanceof CommentNode) {
					CommentNode comment = ((CommentNode) htmlNode);
					comment.getContent().append(" -- By HildaHtmlCleaner");
				}

				// tells visitor to continue traversing the DOM tree
				return true;
			}
		});

		for (String name : list) {
			Log.v("crawDroid", ".HtmlCleaner.getImages: image src = " + name);

		}
		savePaths(list, SdCardUtils.IMAGE_FOLDER);

	}

	private void getCSS(TagNode node) {
		final ArrayList<String> list = new ArrayList<String>();

		// traverse whole DOM and update images to absolute URLs
		node.traverse(new TagNodeVisitor() {
			public boolean visit(TagNode tagNode, HtmlNode htmlNode) {
				if (htmlNode instanceof TagNode) {
					TagNode tag = (TagNode) htmlNode;
					String tagName = tag.getName();
					if ("link".equals(tagName)) {
						String src = tag.getAttributeByName("href");
						if (src != null && src.endsWith(".css")) {
							if (src.startsWith("htt")) {
								list.add(src);
							} else {
								if (src.startsWith("/")) {
									src = src.substring(1);
								}
								if (src.contains("//")) {
									src = src.replace("//", "/");
								}
								if (src.toLowerCase().endsWith("css")) {
									list.add(mURL.toExternalForm() + src);
								}
							}

							// Change absolute url path to relative path
							String[] split = src.split("/");
							tag.setAttribute("href", "css/"
									+ split[split.length - 1]);

						}
					}
				} else if (htmlNode instanceof CommentNode) {
					CommentNode comment = ((CommentNode) htmlNode);

					comment.getContent().append(" -- By HildaHtmlCleaner");
				}

				// tells visitor to continue traversing the DOM tree
				return true;
			}
		});

		for (String name : list) {
			Log.v("crawDroid", ".HtmlCleaner.getCSS: css href = " + name);
		}
		savePaths(list, SdCardUtils.CSS_FOLDER);

	}

	private void savePaths(ArrayList<String> urlOriginList, String where) {
		File file = null;
		URL url = null;

		byte bytes[] = new byte[500];

		for (String urlImgPath : urlOriginList) {

			try {
				url = new URL(urlImgPath);

				// TODO
				// Check if the urlImgPath Host are different from url petition
				if (mURL != null) {
					if (url.getHost().contains(mURL.getHost())) {
						file = mSdCardUtils.prepareFile(url, where);
					} else {
						String imagePath = mURL.getProtocol() + "://"
								+ mURL.getHost() + url.getPath();
						URL imagePathUrl = new URL(imagePath);
						file = mSdCardUtils.prepareFile(imagePathUrl, where);
					}
				}

				if (file == null) {
					Log.e("crawDroid", ".HtmlCleaner.savePaths: "
							+ "File is NULL");
					return;
				}

				InputStream in = url.openStream();
				OutputStream out = new FileOutputStream(file);

				int numRead = 0;
				numRead = in.read(bytes);
				while (numRead != -1) {
					out.write(bytes, 0, bytes.length);
					numRead = in.read(bytes);
				}
				out.close();
				in.close();

			} catch (FileNotFoundException e) {
				Log.e("crawDroid", ".HtmlCleaner.savePaths: " + e.getMessage());
			} catch (MalformedURLException e) {
				Log.e("crawDroid", ".HtmlCleaner.savePaths: " + e.getMessage());
			} catch (IOException e) {
				Log.e("crawDroid", ".HtmlCleaner.savePaths: " + e.getMessage());
			}

		}
	}
}
